/********************************************************************************************/
/*																							*/
/*								Twn_ManBeeper.cpp											*/
/*																							*/
/*	Description:	This library contains functions to signal end of movements in manual	*/
/*					protected and manual witout interlocks operating modes.					*/
/*																							*/
/********************************************************************************************/

#define ALONE_TWN_MAN_BEEPER
#include "Twn_ManBeeper.h"

int			sampleTime;
int			initialWait;
int			cycleTime;
int			cyclesNumber;
TCHAR		endMovSound[256];
TCHAR		failedMovSound[256];

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved){
	LONG	res;
	LPDWORD	type;
	LPBYTE	data;
	LPDWORD size;
	HKEY	hKey;
    DWORD	dwBufLen = MY_BUFSIZE;
	TCHAR	soundPath[256];
	DWORD	active;

	size = 0;
	data = 0;
	type = 0;
	
	
	switch(fdwReason){ 
		case DLL_PROCESS_ATTACH:
			RegOpenKeyEx(	HKEY_LOCAL_MACHINE, 
							TEXT("SOFTWARE\\ABB\\Power Generation Portal\\Tianwan\\Twn_ManBeeper"),
							0,
							KEY_QUERY_VALUE,
							&hKey);
			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("SampleTime"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS)
				sampleTime = (int)active;
			else{
				MessageBox(NULL, _T("Cannot load manual beeper sample time.\nSample time set default value (2 sec.)."), _T("Error"), MB_OK | MB_ICONERROR);
				sampleTime = 2000;
			}

			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("CyclesNumber"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS)
				cyclesNumber = (int)active;
			else{
				MessageBox(NULL, _T("Cannot load manual beeper wait cycles number.\nWait cycles number set default value (2000)."), _T("Error"), MB_OK | MB_ICONERROR);
				cyclesNumber = 2000;
			}

			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("InitialWait"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS)
				initialWait = (int)active;
			else{
				MessageBox(NULL, _T("Cannot load manual beeper initial wait time.\nInitial wait time set default value (2000)."), _T("Error"), MB_OK | MB_ICONERROR);
				initialWait = 2000;
			}

			active = 0;
			dwBufLen = sizeof(active);
			res = RegQueryValueEx(	hKey,
									TEXT("CycleTime"),
									NULL,
									NULL,
									(LPBYTE)&active,
									&dwBufLen);
			if(res == ERROR_SUCCESS)
				cycleTime = (int)active;
			else{
				MessageBox(NULL, _T("Cannot load manual beeper main cycle time.\nMain cycle time set default value (2000)."), _T("Error"), MB_OK | MB_ICONERROR);
				cycleTime = 2000;
			}

			RegCloseKey(hKey);
			
			RegOpenKeyEx(	HKEY_LOCAL_MACHINE, 
							TEXT("SOFTWARE\\ABB\\Power Generation Portal\\Tianwan\\Voldia"),
							0,
							KEY_QUERY_VALUE,
							&hKey);

			dwBufLen = sizeof(soundPath);
			res = RegQueryValueEx(	hKey,
									TEXT("EndMovementSound"),
									NULL,
									NULL,
									(LPBYTE)soundPath,
									&dwBufLen);
			if(res == ERROR_SUCCESS)
				_stprintf_s(endMovSound, soundPath);
			else{
				MessageBox(NULL, _T("Cannot load movement end sound path.\nUsing default file: \"C:\\WinNt\\Media\\Chord.wav\""), _T("Error"), MB_OK | MB_ICONERROR);
				_stprintf_s(endMovSound, _T("C:\\WinNt\\Media\\Chord.wav"));
			}

			dwBufLen = sizeof(soundPath);
			res = RegQueryValueEx(	hKey,
									TEXT("FailedMovementSound"),
									NULL,
									NULL,
									(LPBYTE)soundPath,
									&dwBufLen);
			if(res == ERROR_SUCCESS)
				_stprintf_s(failedMovSound, soundPath);
			else{
				MessageBox(NULL, _T("Cannot load movement failed sound path.\nUsing default file: \"C:\\WinNt\\Media\\Chord.wav\""), _T("Error"), MB_OK | MB_ICONERROR);
				_stprintf_s(failedMovSound, _T("C:\\WinNt\\Media\\Chord.wav"));
			}

			RegCloseKey(hKey);
			break;
		default:
			break;
	}
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

/****************************************************************************************/
/*																						*/
/*	Function:		ManBeeper															*/
/*																						*/
/*	Description:	Execute end movement signals in manual operative modes				*/
/*																						*/
/*	Return:			RETSTAT		-	RT_NORMAL for normal finish							*/
/*									RT_FAILED otherwise									*/
/*																						*/
/*	Author:			M. Tavella															*/
/*																						*/
/*	Date:			24/04/2002															*/
/*																						*/
/****************************************************************************************/
RETSTAT ManBeeper(DWORD opStation){
	RETCOND			retCnd;
	RETSTAT			retSt;
	TAGIDX			startMovIdx;
	TAGIDX			lastOpOKIdx;
	TAGIDX			lastOpNotOKIdx;
	TAGIDX			tagXIdx;
	TAGIDX			tagYIdx;
	GENIDX			mastType;
	GENIDX			movXIdx;
	GENIDX			movYIdx;
	GENIDX			movXYIdx;
	TAGVALEX		tagVal_1;
	TAGVALEX		tagVal_2;
	TAGVALEX		tagVal;
	HWND			hWnd;
	t_rpmb			rpmb;
	bool			opFound;
	TCHAR			mov[128];
	TCHAR			strSp[128];
	TCHAR			tripStr[TRIP_DESCR_LEN];
	TCHAR			msg[256];
	float			sp_1, sp_2, pos_1, pos_2;
	float			sx, sy;
	float			falv_x;
	float			falv_y;
	int				horizFlag;
	int				opMode;
	int				cycles;
	int				tripFlag;
	
	retCnd = GetTagIdx(TWN_START_MOV, &startMovIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_LAST_OP_OK, &lastOpOKIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_LAST_OP_NOOK, &lastOpNotOKIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);
	
	retCnd = GetTagIdx(TWN_BRIDGE_POS, &tagXIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retCnd = GetTagIdx(TWN_TROLLEY_POS,&tagYIdx);
	if(retCnd != R_NORMAL)
		return(RT_FAILED);

	retSt = GetFALVOffset(&falv_x, &falv_y);

	GetMicroCmdIdx(MICRO_MOVEX, &movXIdx);
	GetMicroCmdIdx(MICRO_MOVEY, &movYIdx);
	GetMicroCmdIdx(MICRO_MOVEXY, &movXYIdx);
	while(1){
		retCnd = TagRead(&startMovIdx, &tagVal_1);
		if(retCnd != R_NORMAL)
			return(RT_FAILED);
		
		retSt = GetDynCurrentMode(&opMode);

		if((opMode != M_PROTECT) && (opMode != M_EMERGEN) && (opMode != M_MAN_SINGLE_CH) && (opMode != M_MAN_WO_INT)){	
			goto SLEEP;
		}

		if(GtBit((short int)(tagVal_1.value.val_di), 15) == 1){
			ZeroMemory(&rpmb, sizeof(t_rpmb));
			retSt = GetMovementInProgressEx(mov, &rpmb.movType, &sp_1, &sp_2, &pos_1, &pos_2, &horizFlag);
			if(retSt == RT_NORMAL){
				opFound = true;
				SetSSTREntry(SSTR_TC_REC, _T(""));
				SetSSTREntry(SSTR_OBJ_REC, _T(""));
				SetSSTREntry(SSTR_MECH_REC, mov);
				SetSSTREntry(SSTR_TCSEQ_REC, _T(""));
				if((sp_1 >= 0.0) && (sp_2 == SP_NULL))
					_stprintf_s(strSp, _T("%.1f"), sp_1);
				else if(sp_1 == SP_OPEN)
					_stprintf_s(strSp, _T("Running to OPEN"));
				else if(sp_1 == SP_CLOSE)
					_stprintf_s(strSp, _T("Running to CLOSE"));
				else if((sp_1 != SP_NULL) && (sp_2 != SP_NULL))
					_stprintf_s(strSp, _T("%.1f, %.1f"), sp_1, sp_2);
				if((sp_1 != SP_NULL) && (sp_2 != SP_NULL))
					SetSSTREntry(SSTR_COORD_REC, strSp);
				else
					SetSSTREntry(SSTR_COORD_REC, _T(""));
				rpmb.setPoint = sp_1;
				rpmb.startPos = pos_1;
				if(sp_2 != SP_NULL)
					rpmb.setPoint_2 = sp_2;
				if(pos_2 != SP_NULL)
					rpmb.startPos_2 = pos_2;
				GetDynCurrentMode(&rpmb.opMode);
				GetCurrentUserIdx(opStation, &rpmb.opIdx);
				retCnd = GetApmsTimeEx(&rpmb.startTime);
				if(horizFlag == 1){
					GetDynCurrentMast(&mastType);
					retCnd = TagRead(&tagXIdx, &tagVal);
					if(retCnd != R_NORMAL)
						return(RT_FAILED);
					sx = (float)(tagVal.value.val_float);
					retCnd = TagRead(&tagYIdx, &tagVal);
					if(retCnd != R_NORMAL)
						return(RT_FAILED);
					sy = (float)(tagVal.value.val_float);
					if((mastType == FALC_MAST) || (mastType == DMP_MAST)){
						sx = sx + falv_x;
						sy = sy + falv_y;
					}
					PathStepAdd(mastType, sx, sy, PATH_TYPE_PLAN); 
					if(rpmb.movType == movXYIdx)
						PathStepAdd(mastType, sp_1, sp_2, PATH_TYPE_PLAN); 
					else if(rpmb.movType == movXIdx)
						PathStepAdd(mastType, sp_1, sy, PATH_TYPE_PLAN); 
					else if(rpmb.movType == movYIdx)
						PathStepAdd(mastType, sx, sp_1, PATH_TYPE_PLAN); 
				}
			}
			else
				opFound = false;
			Sleep(initialWait);
			if(!opFound){
				retSt = GetMovementInProgressEx(mov, &rpmb.movType, &sp_1, &sp_2, &pos_1, &pos_2, &horizFlag);
				if(retSt == RT_NORMAL){
					opFound = true;
					SetSSTREntry(SSTR_TC_REC, _T(""));
					SetSSTREntry(SSTR_OBJ_REC, _T(""));
					SetSSTREntry(SSTR_MECH_REC, mov);
					SetSSTREntry(SSTR_TCSEQ_REC, _T(""));
					if((sp_1 >= 0.0) && (sp_2 == SP_NULL))
						_stprintf_s(strSp, _T("%.1f"), sp_1);
					else if(sp_1 == SP_OPEN)
						_stprintf_s(strSp, _T("Running to OPEN"));
					else if(sp_1 == SP_CLOSE)
						_stprintf_s(strSp, _T("Running to CLOSE"));
					else if((sp_1 != SP_NULL) && (sp_2 != SP_NULL))
						_stprintf_s(strSp, _T("%.1f, %.1f"), sp_1, sp_2);
					if((sp_1 != SP_NULL) && (sp_2 != SP_NULL))
						SetSSTREntry(SSTR_COORD_REC, strSp);
					else
						SetSSTREntry(SSTR_COORD_REC, _T(""));
					rpmb.setPoint = sp_1;
					rpmb.startPos = pos_1;
					if(sp_2 != SP_NULL)
						rpmb.setPoint_2 = sp_2;
					if(pos_2 != SP_NULL)
						rpmb.startPos_2 = pos_2;
					GetDynCurrentMode(&rpmb.opMode);
					GetCurrentUserIdx(opStation, &rpmb.opIdx);
					retCnd = GetApmsTimeEx(&rpmb.startTime);
					if(horizFlag == 1){
						GetDynCurrentMast(&mastType);
						retCnd = TagRead(&tagXIdx, &tagVal);
						if(retCnd != R_NORMAL)
							return(RT_FAILED);
						sx = (float)(tagVal.value.val_float);
						retCnd = TagRead(&tagYIdx, &tagVal);
						if(retCnd != R_NORMAL)
							return(RT_FAILED);
						sy = (float)(tagVal.value.val_float);
						if((mastType == FALC_MAST) || (mastType == DMP_MAST)){
							sx = sx + falv_x;
							sy = sy + falv_y;
						}
						PathStepAdd(mastType, sx, sy, PATH_TYPE_PLAN); 
						if(rpmb.movType == movXYIdx)
							PathStepAdd(mastType, sp_1, sp_2, PATH_TYPE_PLAN); 
						else if(rpmb.movType == movXIdx)
							PathStepAdd(mastType, sp_1, sy, PATH_TYPE_PLAN); 
						else if(rpmb.movType == movYIdx)
							PathStepAdd(mastType, sx, sp_1, PATH_TYPE_PLAN); 
					}
				}
				else if(retSt == RT_INVMICR){
					SetSSTREntry(SSTR_MECH_REC, _T("Error retrieving movement in progress"));
					SetSSTREntry(SSTR_COORD_REC, _T("Error retrieving movement in progress"));
				}
			}
			Sleep(5000);
			for(cycles = cyclesNumber; cycles > 0; cycles--){
				retCnd = TagRead(&startMovIdx, &tagVal_1);
				if(retCnd != R_NORMAL)
					return(RT_FAILED);
				if(GtBit((short int)(tagVal_1.value.val_di), 15) == 0){

					Sleep(WAIT_BEFORE_LASTOP);

					retCnd = TagRead(&lastOpOKIdx, &tagVal_1);
					if(retCnd != R_NORMAL)
						return(RT_FAILED);

					retCnd = TagRead(&lastOpNotOKIdx, &tagVal_2);
					if(retCnd != R_NORMAL)
						return(RT_FAILED);

					SetSSTREntry(SSTR_TC_REC, _T(""));
					SetSSTREntry(SSTR_OBJ_REC, _T(""));
					SetSSTREntry(SSTR_MECH_REC, _T(""));
					SetSSTREntry(SSTR_TCSEQ_REC, _T(""));
					SetSSTREntry(SSTR_COORD_REC, _T(""));

					if((GtBit((short int)(tagVal_1.value.val_di), 15) == 0) && (GtBit((short int)(tagVal_2.value.val_di), 15) == 1)){
						//Error//
						retSt = GetTripInfo(&tripFlag, tripStr);
						if(retSt != RT_NORMAL){
							tripFlag = TRIP_OFF;
						}
						if(tripFlag == TRIP_OFF){
							if(opFound)
								_stprintf_s(msg, _T("Movement of mechanism(s) %s stopped."), mov);
							else
								_stprintf_s(msg, _T("Movement stopped."));
						}
						else{
							if(opFound)
								_stprintf_s(msg, _T("Movement of mechanism(s) %s failed."), mov);
							else
								_stprintf_s(msg, _T("Movement failed."));
						}
						rpmb.result = RPMB_OP_NOOK;
						retCnd = GetApmsTimeEx(&rpmb.endTime);
						retSt = SetRPMB(0, rpmb);
						
						PlaySound(failedMovSound, NULL, SND_FILENAME);
						hWnd = FindWindow(NULL, _T("Manual Mode Management"));
						MessageBox(hWnd, msg, _T("Movement terminated"), MB_OK | MB_ICONINFORMATION);
						goto SLEEP;
					}
					else if((GtBit((short int)(tagVal_1.value.val_di), 15) == 1) && (GtBit((short int)(tagVal_2.value.val_di), 15) == 0)){
						//Success//
						if(opFound)
							_stprintf_s(msg, _T("Movement of mechanism(s) %s completed."), mov);
						else
							_stprintf_s(msg, _T("Movement completed."));
						rpmb.result = RPMB_OP_OK;
						retCnd = GetApmsTimeEx(&rpmb.endTime);
						retSt = SetRPMB(0, rpmb);
						
						/*
						for(beepCount = 0; beepCount < MB_END_BEEP_TIME; beepCount++){
							Beep(MB_END_BEEP_FREQ, MB_END_BEEP_LEN);
							Sleep(MB_END_BEEP_SLEEP);
						}
						*/
						PlaySound(endMovSound, NULL, SND_FILENAME);
						hWnd = FindWindow(NULL, _T("Manual Mode Management"));
						MessageBox(hWnd, msg, _T("Success"), MB_OK | MB_ICONINFORMATION);
						goto SLEEP;
					}
					else if((GtBit((short int)(tagVal_1.value.val_di), 15) == 0) && (GtBit((short int)(tagVal_2.value.val_di), 15) == 0)){
						//Undefined result//
						if(opFound)
							_stprintf_s(msg, _T("Movement of mechanism(s) %s has been stopped."), mov);
						else
							_stprintf_s(msg, _T("Movement has been stopped."));
						rpmb.result = RPMB_OP_STOPPED;
						retCnd = GetApmsTimeEx(&rpmb.endTime);
						retSt = SetRPMB(0, rpmb);
						/*
						for(beepCount = 0; beepCount < MB_FAILED_BEEP_TIME; beepCount++){
							Beep(MB_FAILED_BEEP_FREQ, MB_FAILED_BEEP_LEN);
							Sleep(MB_FAILED_BEEP_SLEEP);
						}
						*/
						PlaySound(failedMovSound, NULL, SND_FILENAME);
						//if(opMode == M_MAN_WO_INT)
						hWnd = FindWindow(NULL, _T("Manual Mode Management"));
						MessageBox(hWnd, msg, _T("Movement stopped"), MB_OK | MB_ICONINFORMATION);
						goto SLEEP;
					}
					else{
						//Undefined result//
						if(opFound)
							_stprintf_s(msg, _T("Movement of mechanism(s) %s returned an undefined result."), mov);
						else
							_stprintf_s(msg, _T("Movement returned an undefined result."));
						rpmb.result = 0;
						retCnd = GetApmsTimeEx(&rpmb.endTime);
						retSt = SetRPMB(0, rpmb);
						/*
						for(beepCount = 0; beepCount < MB_FAILED_BEEP_TIME; beepCount++){
							Beep(MB_FAILED_BEEP_FREQ, MB_FAILED_BEEP_LEN);
							Sleep(MB_FAILED_BEEP_SLEEP);
						}
						*/
						PlaySound(failedMovSound, NULL, SND_FILENAME);
						hWnd = FindWindow(NULL, _T("Manual Mode Management"));
						MessageBox(hWnd, msg, _T("Warning"), MB_OK | MB_ICONWARNING);
						goto SLEEP;
					}
				}
				Sleep(cycleTime);
			}
		}
SLEEP:
		Sleep(sampleTime);
	}
	return(RT_NORMAL);
}
